package net.zdsoft.wpchat.support.client;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

import net.sf.json.JSONObject;
import net.zdsoft.keel.action.Action;
import net.zdsoft.keel.action.ActionContext;
import net.zdsoft.keel.action.ActionInvoker;
import net.zdsoft.keel.action.Messageable;
import net.zdsoft.keel.interceptor.Interceptor;
import net.zdsoft.keel.util.ActionUtils;
import net.zdsoft.keel.util.ServletUtils;
import net.zdsoft.keel.util.StringUtils;
import net.zdsoft.wpchat.support.entity.UserConfig;
import net.zdsoft.wpchat.support.entity.UserOperation;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 后台权限控制拦截器
 *
 * @author xuan
 */
public class AuthorizerInterceptor implements Interceptor {
    private static Logger logger = LoggerFactory.getLogger(AuthorizerInterceptor.class);

    private static final String FRAME = "/support/frame";
    private static final String TARGET_LOGIN = "supportIndex";
    private static final String TARGET_ERROR = "supportError";

    @Override
    public void init() {
    }

    @Override
    public void destroy() {
    }

    @Override
    public String intercept(ActionInvoker invoker) throws Exception {
        String namespace = invoker.getActionPackage().getNamespace();
        String actionName = invoker.getServiceMapping().getMarkedName();
        String actionPath = namespace + "/" + actionName;

        logger.debug("actionPath: " + actionPath);

        Object action = invoker.getActionInstance();
        MemoryUser user = (MemoryUser) ActionContext.getSession().getAttribute(MemoryUser.KEY);
        if (null == user) {
        	//未登录跳转到登录页面
            ActionContext.getSession().setAttribute(Action.LOGIN, new Boolean(true));
            if (ActionUtils.isJsonAction(invoker)) {// Json方式调用
                printRefreshPageJson();
            }

            return TARGET_LOGIN;
        }

        if (!FRAME.equals(namespace)) {
            // 复杂权限判断
            UserConfig userConfig = user.getUserConfig();
            UserOperation userOperation = userConfig.getUserOperation(namespace, actionName);
            // 如果普通方式的action映射不在权限许可内, e.g. action
            // 继续进行指定方法名称方式的action映射, e.g. action!method
            if (null == userOperation) {
            	logger.debug("Requested action style 1[" + namespace + "." + actionName + "]");
                actionName = invoker.getServiceMapping().getMarkedName();
                logger.debug("Requested action style 2[" + namespace + "." + actionName + "]");

                userOperation = userConfig.getUserOperation(namespace, actionName);
                if (null == userOperation) {
                    logger.error("用户(" + user.getUsername() + ")没有访问权限[" + namespace + "." + actionName + "]");
                    addError(action, "您没有权限执行这个操作");
                    return TARGET_ERROR;
                }
            }
            else {
                UserAuth userAuth = new UserAuth(userConfig, userOperation);
                ActionContext.getRequest().setAttribute(UserAuth.KEY, userAuth);
            }
        }

        String target = null;
        try {
            target = invoker.invoke();
        }
        catch (Throwable e) {
            logger.error("Could not invoke action[" + actionName + "] by user[" + user.getUsername() + "]", e);

            addException(action, e);
            target = TARGET_ERROR;
        }

        return target;
    }

    // 将错误信息添加到Action Error中.
    private void addError(Object action, String message) throws IOException {
        if (action instanceof Messageable) {
            ((Messageable) action).addActionError(StringUtils.htmlFilter(message));
        }
    }

    // 将异常信息添加到Action Error中
    private void addException(Object action, Throwable e) throws IOException {
        if (action instanceof Messageable) {
            StringWriter out = new StringWriter();
            e.printStackTrace(new PrintWriter(out));
            ((Messageable) action).addActionError(StringUtils.exceptionFilter(out.getBuffer().toString()));
            out.close();
        }
    }

    //以Json的方式打印出
    protected void printRefreshPageJson() throws IOException {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("script", "location.href = location.href;");
        jsonObject.put("actionErrors", new String[] { "对不起，您没有登录或者已经超时，系统将转向登录页面！" });
        ServletUtils.print(ActionContext.getResponse(), jsonObject.toString(), "application/json");
    }

}
